package org.kolonitsky.alexey.net
{
    import com.adobe.serialization.json.JSON;
    
    import flash.events.ErrorEvent;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.events.HTTPStatusEvent;
    import flash.events.IEventDispatcher;
    import flash.events.IOErrorEvent;
    import flash.events.SecurityErrorEvent;
    import flash.net.URLLoader;
    import flash.net.URLRequest;

    import org.kolonitsky.alexey.debug.DebugWrapper;

    import utils.Logger;


    /**
     * Loading JSON file.
     * 
     * @author Alexey Kolonitsky
     * @date 25.05.2009
     */  
    public class JSONService extends EventDispatcher 
    {
        /**
         *  Constructor 
         */
        public function JSONService(uri:String="", target:IEventDispatcher=null):void
        {
            super(target);
            _uri = new URLRequest();
            _uri.url = uri
        }
        
        
        /** 
         *  Load xml
         *  After loading content availabel in lastData field.
         * 
         *  @param uri can be String or URLRequest.
         */ 
        public function load (uri:*): void 
        {
            if (uri is String) 
                _uri.url = uri;
            if (uri is URLRequest)
                _uri = uri as URLRequest;
            loader = new URLLoader();
            loader.addEventListener(Event.COMPLETE, loader_completeHandler);
            loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
            loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSequrityError);
            loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, loaderHTTPStatusHandler);
            loader.load(_uri);
        }

        /**
         * Remove event listeners and clear all private data.
         */
        public function clear ():void
        {
            removeListeners();
            loader.close();
            loader = null;
            _data = null;
        }
        
        /**
         *  Last successful loaded data parserd to AS object.
         */ 
        public function get lastData ():Object 
        {
            return _data;
        }

        /**
         *
         */
        public function get uri():URLRequest
        {
            return _uri;
        }
        
        
        
        //----------------------------------------------------------------------
        //
        // Protected
        //
        //----------------------------------------------------------------------
        
        protected var _uri:URLRequest;
        
        protected var _data:Object;
        
        
        //----------------------------------------------------------------------
        //
        // Private logic
        //
        //----------------------------------------------------------------------
        
        private var loader:URLLoader;

        private var _httpCode:int = -1;

        /**
         * Convert passed object to object and save it to lastData
         * @param data
         */
        private function saveData(data:Object):void
        {
            var str: String = String(data);
            if (str == null || str.length == 0)
                return;

            try
            {
                _data = com.adobe.serialization.json.JSON.decode(str);
            }
            catch (error:Error)
            {
                Logger.error(_uri.url + " response is malformed." +
                    "\n\t\tParser Error: " + error.message, this);
            }
        }
        
        protected function loader_completeHandler (event:Event): void
        {
            switch (_httpCode)
            {
                case 0:
                case 200:
                case 404:
                case 401:
                {
                    Logger.log("complete, " + _httpCode + ": " + _uri.url, this);
                    saveData(event.target.data);
                    if (_data && "errorCode" in _data && "errorDescription" in _data)
                    {
                        event.stopImmediatePropagation();
                        dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, true, false, _data.errorDescription, _data.errorCode));
                    }
                    else
                    {
                        dispatchEvent(new Event(Event.COMPLETE));
                    }
                    break;
                }

                default:
                {
                    DebugWrapper.warning("Unhandled http status: " + _httpCode, this);
                    break;
                }
            }
            removeListeners();
        }
        
        protected function onIOError(event:IOErrorEvent):void
        {
            saveData(event.target.data);
            var errorEvent:ErrorEvent;
            var message:String = "";
            if (_data)
            {
                message = _data.error || _data.errorDescription;
                errorEvent = new ErrorEvent(ErrorEvent.ERROR, true, false, message, _data.errorId)
            }
            else
            {
                errorEvent = new ErrorEvent(ErrorEvent.ERROR, true, false, event.text, event.errorID);
            }
            dispatchEvent(errorEvent);
            removeListeners();
        }
        
        protected function onSequrityError(event:SecurityErrorEvent):void
        {
            DebugWrapper.error("onSequrityError() " + event.text, this);
            dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, true, false,  event.text));
            removeListeners();
        }
        
        protected function loaderHTTPStatusHandler(event:HTTPStatusEvent):void
        {

            _httpCode = event.status;
//            trace("DEBUG: JSONService.HTTPStatus, status=" + event.status);
        }

        private function removeListeners():void
        {
            if (loader)
            {
                loader.removeEventListener(Event.COMPLETE, loader_completeHandler);
                loader.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
                loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onSequrityError);
                loader.removeEventListener(HTTPStatusEvent.HTTP_STATUS, loaderHTTPStatusHandler);
            }
        }
   }
}